Skip to content

Shield and Swap screens, a terminal-aware std, and a TLS check the wallet was missing - #583

Open
eKisNonos wants to merge 29 commits into
linux/store-installfrom
ui/shield-swap-terminal
Open

eKisNonos wants to merge 29 commits into
linux/store-installfrom
ui/shield-swap-terminal

Conversation

@eKisNonos

@eKisNonos eKisNonos commented Sep 28, 2026 •

Copy link
Copy Markdown
Contributor

Stacked on #567. This PR targets linux/store-install so it shows only its own 29 commits: 9 terminal commits that were already on ui/terminal, and 20 new ones. When #567 merges into main, retarget this PR to main.

Each commit builds on its own. The wallet and terminal were checked live on a 1920x1080 QEMU boot of the image built from this branch.

Kernel and std

  • kernel: tell a program whether its streams reach a terminal adds a tty table, sys_tty_set (parent only, needs the IPC capability) and sys_tty_query, which answers rows and columns or ENOTTY.
  • std: ask the kernel whether a standard stream is a terminal makes is_terminal real in the std layer. Tools such as pastel now colour their output on a screen and stay plain in a pipe, without being patched.
  • build: drop std build caches when the std layer changes fixes a stale-std hazard: -Zbuild-std did not rebuild std when rust-src changed underneath it.

Terminal and toolkit

  • Readline keys and chords that type nothing.
  • Help that fits 80 columns and names every key, with tests.
  • rg dropped, since no build registers it, and refusals named.
  • Selection can start in the margin.
  • The terminal tells the programs it runs that they reach a screen, and updates them on resize.
  • Commands longer than the screen is wide (LINE_MAX 1024).
  • Sixteen colours per theme, each held to WCAG contrast by a test.
  • Box-drawing characters stroked across the whole cell, so tables join. This was checked live with csview.
  • The toolkit draws characters the UI face lacks from the mono face.
  • The editor draws folder chevrons in pixels and colours only code.

Wallet

  • talk to the RPC only after the server proves it is the host: TLS 1.3 CertificateVerify is now checked (RFC 8446 4.4.3) before any request is written. Before this, the chain was checked but the server never had to prove it held the key.

  • show the recovery phrase, and make Esc go back: the phrase is shown once, in a numbered grid. Esc goes back one step instead of closing the window.

  • refuse to sign a transfer above a 1000 gwei gas price.

  • draw the Shield screens and say when no shield service answers:

    • home, with shielded balances first and the nox1 receive address;
    • deposit and withdraw in the pool's standard sizes only (0.01 to 10 ETH, 1,000 to 5,000,000 NOX);
    • private send, with the sentence the pool asks every wallet to show;
    • review, proof progress, history, and the Sepolia contracts written out in full.

    Spending a note before the 20-note, 6-hour wait needs the typed words "spend early". A nox1 address is pasted with Ctrl+V.

  • make a withdrawal wait like a payment: found on the live boot, where Review withdrawal was enabled with the wait not even counted. The same commit resets the size between screens and makes the banner's Dismiss work.

  • draw Swap on the Etna frame: rate, price impact, minimum received, slippage, fee and route in one open tile. Picking the token already on the other side swaps the pair.

What is not wired, and says so

  • Shield: Confirm goes through a single request seam in screen/shield/request.rs. It refuses with a sentence while no shield service answers, and while this build cannot yet speak the service's request format.
  • Swap: the quote source is still the stub, so no trade is priced or sent. The screen shows a banner instead of a zero price.
  • History and proofs show only what the shield service reports. Nothing is invented.

Checked

  • cargo check for x86_64-nonos-user, with no new errors; the only new warnings are dead code for history states the shield service will fill.
  • Every new file is at most 75 lines.
  • The size ladder was run on the host against the expected wei values.
  • A live boot walk-through of Shield home, Deposit, Review, Send with the override, Withdraw, History, Sepolia and Swap. Screenshots are available on request.

With NONOS_LINUX_GUESTS=1 the kernel was still built with the setup
profile. Under it the apps, the Linux personality among them, spawn only
once first-boot setup exits, and setup waits for keys. An unattended guest
boot therefore never started its guest: in 180 s after `[INIT] Capsules
spawned` the log had `[SETUP] keyboard held` and no `[APP-LINUX]` or
`[LINUX]` line.

That image now builds `microkernel-desktop-gui` with `nonos-stark-attest`,
the same capsule set without setup, so the apps spawn at boot. Every other
build of nonos-mk-desktop-gui-prod is unchanged.
Threads run on their leader's tables without owning an address space
entry, so release freed the tables when the leader was finalized, whatever
its threads were doing. A thread still in the process table can be on the
CPU under those tables, taking its own kill. When a Go guest exited, the
personality killed its threads and then its leader, and the timer drain
finalized the leader while a Go thread was running. The kernel then took a
page fault fetching the double fault gate, and the machine reset:
CR3 was the guest's, FS held the Go thread's TLS, and CR2 was the IDT's
entry for vector 8.

Release now hands the address space to another process in the table that
runs on the same tables, and rebinds that process's capability token to
the ASID it now owns. The last holder's release frees the tables.
A Linux clone child resumes after its parent's `syscall` holding the
parent's registers, with rax zero and rsp the new stack. MkForeignThread
started the child on fresh registers instead, and both runtimes that start
threads here call through a register in the child: Go's `runtime.clone`
calls r12 and reads m and g from r13 and r9, and musl 1.2.4's `__clone`
calls r9. The first gohello boot started two threads, and they faulted at
`rip=0` and at a heap address on an NX page.

MkForeignThread takes a fifth argument, the guest thread parked in the
call that asked. Given, the new thread starts on a copy of that thread's
parked registers, with rax zero, the entry and stack given, and the
parent's FS base unless a TLS is named. The source thread must be
supervised by the caller and in the same thread group as the target, so no
guest receives another's register contents. Zero keeps the fresh start.

The personality passes the calling thread, and passes a TLS only when
CLONE_SETTLS is set; before, a clone without it installed the fifth
argument, whatever it held, as the child's FS base.
MkKill admitted a parent or a holder of ProcessControl. A guest thread's
parent is its group leader, not the supervisor, so when a Linux guest
exited, the personality's kill of each thread was refused with EPERM, and
the refusal was dropped. The threads outlived their process. Once the
personality had exited, their parked calls were abandoned and they ran Go
code with no one to answer them: a second goconc boot showed a guest
thread faulting at 0x1006 and then at address zero after `[LINUX] guest
exited`.

MkKill now also admits the caller the foreign registry names as the
target's supervisor. The personality prints a refused kill as
`[LINUX] kill refused: pid <n> outlives its process, errno <e>`, so a
thread that survives its process is named in the log.
Pressing the close button now asks the app first, through close_requested.
An app holding unsaved work returns false and says so in its own window; the next press closes. The default closes as before, so no other app changes.
A failed open no longer renames the tab, so the next save cannot write the old text over the file that failed, and a failed open from the tree opens no tab. Opening puts the file in its own tab and never replaces text; a load resets undo, redo and selection. A new document is untitled instead of carrying /notes.txt unread, and saving it asks for a path. Save As asks before replacing another file, and a document takes a new name only once the write lands.

Undo and redo track a save point, so undoing back to the saved text is clean and undoing past it is not, even after old steps are dropped. Every close control and the window close button ask once before discarding unsaved text, and Esc no longer closes the window. editor_proofs compiles again, with save-point proofs: 34 pass.
A no_std crate the terminal will draw from. The parser is the DEC state machine: CSI with private markers, colon sub-parameters and intermediates, OSC, DCS, SOS/PM/APC swallowed, CAN/SUB/ESC aborting any sequence, UTF-8 split across reads. The screen defers the wrap at the last column, so a full-screen program can fill the bottom-right cell, and implements IL, DL, RI, SU, SD, ICH, DCH, ECH, REP, tab stops, origin and insert modes, DECSC/DECRC, the 47/1047/1048/1049 alternate screens, DEC line drawing, wide characters kept whole, and combining marks and ZWJ sequences in one cell. Resize re-wraps the normal screen and its history.

It answers DA1, DA2, DSR, DECRQM, XTVERSION, XTGETTCAP, DECRQSS, size reports and OSC colour queries, since editors wait for them. A program may not move or resize its window, and a clipboard read (OSC 52 ?) is refused and counted. Keys, mouse (X10 and SGR), focus and paste encode per mode; paste strips escape bytes so pasted text cannot end the bracket and run as commands. Every buffer output can grow has a ceiling in limits.

69 tests, including a seeded mutation fuzz that interleaves hostile output with resizes, copies and searches and checks the cursor and row widths after every step; it found a cursor left below the screen after a resize, fixed here.
The PS/2 keymap already emits Insert as 0x1209 and F1 to F12 as 0x1101 to 0x110C.
Apps had no names for them, so none handled them.
The fixed 96x40 grid and its partial VT layer give way to nonos_vt. The screen follows the window size and zoom, re-wrapping on resize, with 3000 lines of history a tab on a 64 MiB heap, and draws bold, dim, every underline style, strikethrough, overline, inverse, hidden, wide and combining characters, and the cursor shape a program sets. A program in the foreground or on the alternate screen owns the body; the prompt returns when it ends, with any modes it left on reset, and output is read up to 64 KiB a tick instead of 256 bytes.

A program reading raw gets keys as xterm sends them (taken as raw once it asks for the alternate screen, application cursor keys, bracketed paste or mouse reports, as there is no path for its tty settings yet); any other gets lines edited as a tty's canonical mode edits them. Ctrl+C interrupts, and a program's queries are answered on its stdin.

The pointer selects text (double click a word or path, triple click a line, Alt for a block), or goes to a program that asked for mouse reports unless Shift is held. Ctrl+Shift+C copies, Ctrl+Shift+V pastes, Ctrl+Shift+F searches history across wrapped lines, and the wheel scrolls history or sends cursor keys on the alternate screen. Proofs for the line editing and selection added to terminal_line_proofs.
A launcher that renders a child's output knows which of the child's
standard streams reach its screen; the child had no way to ask. MTTY lets
the parent record that, with the size in cells, under the same parent
rule that lets it drain the child's output, and it needs IPC as MTRN
does. MTTQ answers the caller about its own stream 0, 1 or 2 with the
size, or ENOTTY. The record is dropped as the process is finalized, so a
reused pid starts with no terminal. Both calls are published in the ABI
with libc wrappers, and the syscall checks pass with the unreachable
count unchanged.
Three answers disagreed on NONOS: std's IsTerminal fell to the
unsupported arm and said no, the vendored is-terminal said no, and the
atty shim said yes for every stream, so one tool could colour a pipe
while another printed plain text to a person. std now asks MTTQ for
streams 0 to 2, and both is-terminal copies and atty go through std, so
there is one answer and it is the launcher's.
Noto Sans has no arrows, no triangles and no not-equal sign, so every app
that printed one showed an empty box. A character the chosen built-in
face lacks is drawn from the other one when that has it, cached under the
face it came from, and measured the same way so layout and paint agree.
Kerning only pairs glyphs of one face.
The explorer drew its chevrons as characters the UI font does not have,
so every folder showed a box. They are now drawn on the pixel grid. The
code lexer ran over every buffer, so a note coloured `from` as a keyword
and a Markdown heading as a comment; plain text and Markdown are now
left as typed.
A Ctrl or Alt chord the line editor did not bind fell through to the
printable arm, so Ctrl-F typed an f. Unbound chords are now swallowed,
AltGr excepted since some layouts type characters with it. Ctrl-F and
Ctrl-H step and rub out a character, Ctrl-P and Ctrl-N walk history, and
Alt-B, Alt-F and Alt-D move and cut by word, with Alt-D's cut going to
the ring Ctrl-Y reads. The skeleton exports MOD_ALTGR, which the PS/2
driver already sets. The arrow and page keys move to their own file.
The help tests parsed writeln calls that the table-driven help no longer
makes, so they read three rows and failed. The tables and row layout now
live in a file the proofs include, and the tests render every row the
terminal prints. That found the files and system rows at 82 and 85
columns; they are regrouped into files, disk, text, system and session.
The tools row names each program once. help keys now covers selection,
the clipboard, search and the readline keys.
rg and ripgrep mapped to tool.ripgrep, which the kernel's tool registry
has never held: the ripgrep capsule is a boot-time service MkToolRun
cannot reach. Typing either printed "tool: launch failed" in every
build. A proof now checks each tool the terminal offers against
apps.list, and a refused launch names the tool and says whether it is
missing from the build or was refused.
A press a few pixels left of the first column landed outside the cell
grid and started nothing. The hit area now takes in the margin painted
around the text, and the column clamps to the edge cell. The pixel to
cell maths moves to its own file.
A tool, store tool or exec'd program whose output this terminal renders
is told, through MTTY, that its three standard streams reach a terminal
of the current size, so it chooses colour and columns for a person. A
pipeline stage or redirected command is never told and writes plain
bytes. When the window resizes, the program in front is told the new
size.
-Zbuild-std fingerprints the sysroot crates by version rather than by
their sources, so a tool whose target dir already held a std kept
linking it after the NONOS std layer changed. Six of the tools shipped
that way without the new terminal query, and pastel still printed its
pipe output to a person. Applying the layer now clears the per-tool std
caches it just made stale.
The line buffer, the history and the kill ring were sized by COLS, the
screen's starting width of 96, so a longer command was cut at column 96.
An echo with a redirect lost its file name there and wrote to a
different file. Typed input now holds LINE_MAX, 1024 bytes, and the
prompt already scrolls sideways across a line wider than the window.
Programs name colours 0 to 15 and got xterm's, whose blue is #0000EE:
2.2:1 against the dark themes, so tokei's table headers could not be
read. Each theme's ground now picks a dark or a light set, and a proof
holds every text colour at 4.5:1 or better on every shipped ground.
A font draws a line character inside its glyph box, so the line gap left
a break between rows and csview's tables did not join. The light, heavy,
double and rounded line characters are now stroked from edge to edge of
the cell, arms meeting at the centre, and anything else still comes from
the font.
The chain, anchor, hostname and validity checks ran only on the probe
connection, where they set status text. The connection that reads
balances, the nonce and the fee, and broadcasts, checked nothing but the
server's Finished, and CertificateVerify was never checked anywhere. A
server that replays the real chain and finishes the handshake on keys of
its own passed, and could name any gas price the wallet then signed at.

CertificateVerify is now verified with the leaf's own key over the
transcript to the Certificate, and every RPC call requires it together
with the chain, the pinned root, the hostname, validity against the
clock, and Finished. ClientHello offers only the ECDSA schemes there is
a verifier for.
Creating a wallet set the backup flag, but the Etna Receive screen was
drawn over it, so the phrase never appeared, and the next Enter wiped
it. On a machine that cannot seal keys the account then lived only in
RAM with no way back. The phrase now has its own screen, straight after
creation, with no back button: confirming is the only way on, and it
wipes the words.

Esc used to close the window before any handler saw it, so every "Esc to
cancel" on screen was dead. It now closes an open panel, returns other
screens home, and does nothing at home.
The fee cap is twice the node's gas price with no upper bound, so a
broken node's reading would be signed as given. A transfer is now
refused above 1000 gwei, and the reason the refresh failed is the one
shown, instead of a single message for every cause.
Shield opened the old dashboard. It now has its own Etna screens: home
with shielded balances first and the nox1 receive address, deposit and
withdraw in the pool's standard sizes only (0.01 to 10 ETH, 1,000 to
5,000,000 NOX), private send with the sentence the pool asks every
wallet to show, review, proof progress, history and the Sepolia
contracts in full.

The spend wait is a meter of 20 new notes and 6 hours; spending early
needs the typed words "spend early". A nox1 address is pasted with
Ctrl+V, since it is too long to type.

Nothing here pretends. Balances read from the note store show a dash
until notes exist, history and proofs show only what the shield
service reports, and Confirm goes through one request seam that
refuses with a sentence while this build cannot yet speak the
service's format.
A withdrawal spends a note, so it now waits for the same 20 new notes
and 6 hours as a private payment, or the typed "spend early", before
it can be reviewed. The walk-through on the live image let one through
with the wait not even counted.

Each choosing screen starts with no size picked; the 10,000 NOX picked
on Deposit had been carried into Withdraw. The no-service banner's
Dismiss now hides it until Shield is next opened, where it did nothing.
The Sepolia page's labels are capitals like every other label.
Swap opened the old dashboard. It now has its own screen: the token
paid and the amount typed, the token bought and what the pool says
comes back, then rate, price impact, minimum received, slippage,
network fee and route in one tile, with a warning in words when the
impact is large. Picking the token already on the other side swaps
the pair, so a token is never traded for itself.

The quote source is still the stub, so an amount gets no price. The
screen says that in a banner instead of showing zero, and the button
stays "Enter an amount". Nothing signs a swap in this build.
The Swap screen's no-price banner drew a Dismiss that did nothing; it now hides the banner until the amount is edited. The early-spend warning said "this payment" on the Withdraw screen too, and now reads for either.
@eKisNonos
eKisNonos changed the base branch from main to linux/store-install September 28, 2026 19:58
@senseix21

Copy link
Copy Markdown
Collaborator

Reviewed at 23f3c5599 (not a draft, base linux/store-install, 408 files, +14331/−2195, 127 commits behind main, last pushed 2026-09-28). An integration branch: it contains #567, #544 and #545, and does not contain #582. New userland/nonos_vt at +7303, capsule_wallet_nonos +4925, capsule_terminal +2785/−1757, plus zstd, openpgp and xz.

Verdict: Comment. 112 lanes pass and the eight that fail are inherited from #567 with one false positive of its own. The reason to read this PR carefully is 55c3c7f2b, which fixes the most serious defect I have found anywhere in this queue.

The wallet was talking to an unauthenticated server

55c3c7f2b's commit message is worth quoting because the diagnosis is exact:

The chain, anchor, hostname and validity checks ran only on the probe connection, where they set status text. The connection that reads balances, the nonce and the fee, and broadcasts, checked nothing but the server's Finished, and CertificateVerify was never checked anywhere.

Two separate failures compounding. The first is a split between a connection that checks and a connection that is used — the probe validated the chain in order to display a status line, and the RPC connection that actually carries money validated almost nothing. The second is worse and independent: CertificateVerify was never verified at all, on either connection.

Without CertificateVerify there is no proof the peer holds the private key for the leaf it presented. Anyone can replay a real certificate chain; the signature over the handshake transcript is the only thing that distinguishes the server from someone who copied its certificate. So, as the message says, "A server that replays the real chain and finishes the handshake on keys of its own passed, and could name any gas price the wallet then signed at."

I verified the fix end to end rather than taking the message for it:

  • tls13/server_trusted_flight.rs is a hard AND of seven checks — chain, anchor, signature, hostname, validity, CertificateVerify, Finished — with the invariant written above it: "The data path asks this, not the probe, so a status line can never stand in for a check." That is the right lesson drawn from the right bug.
  • There is exactly one caller, and it is the data path: wallet/net/fetch_rpc.rs:40. One chokepoint rather than per-call checks that can be forgotten.
  • It fails closed, before any application data moves:
let now = super::rtc_stamp::rtc_stamp()?;
if !super::super::tls13::server_trusted_flight(&flight, &server, ETH_RPC_HOST, now) {
    return None;
}
let http = super::super::rpc::http_post(ETH_RPC_HOST, body);

The return None precedes http_post and application_write, so nothing is sent to an unproven server. And rtc_stamp()? means an unreadable clock aborts the call rather than skipping the validity check — the comment says so explicitly: "A clock that cannot be read fails the check." That is the correct direction for a check that depends on time.

  • ext_sigalgs.rs narrows ClientHello to "only the ECDSA schemes there is a verifier for". Offering a scheme you cannot verify is how a peer talks you into one you will accept without checking, so this belongs in the same commit and is in it.

49dffbb1e ("refuse to sign a transfer above a 1000 gwei gas price") is the defence-in-depth companion — it bounds the damage from the exact lever the TLS bug exposed. Fixing the authentication and capping the signable gas price in the same branch is the right pair.

Important

1. Eight failing lanes, all inherited from #567, and one new hygiene violation that is a false positive.

The inherited set is the one every branch carrying #567 shows: abi-contracts (the assumption register), crypto-proofs (the crypto_proofs mirror includes against_pedersen.rs but not against_root.rs, its only non-test caller), evidence-manifest (stale EVIDENCE.json), proof-crates (capsule_linux_proofs) (mutation_tests.rs:35, 0xDEB5_EEDu64), and build/production-build/benchmark from tcb-budget. runnable-proofs is green here, unlike on #567 itself, so something in this branch already fixed that harness.

hygiene has two violations. I ran a faithful reimplementation of nonos-verify hygiene's scanner over src and userland at this head:

userland/capsule_wallet_nonos/src/wallet/etna/parts/fact.rs:18:placeholder-comment
userland/nonos_vt/src/width/check.rs:32:unwrap

The first is #567's — a doc comment flagged for containing the word "placeholder" while stating the rule the scanner enforces. The second is this PR's, and it is also a false positive:

#[test]
fn tables_are_sorted_and_disjoint() {
    assert!(sorted(ZERO_LOW) && sorted(ZERO_HIGH) && sorted(WIDE));
    assert!(ZERO_LOW.last().unwrap().1 < ZERO_HIGH[0].0);
}

That is a unit test asserting the width tables are sorted and disjoint so the binary search is sound — exactly the kind of unwrap that should be allowed. The scanner has no notion of #[test] context.

That makes three of three hygiene violations across this entire PR queue false positives, each for a different reason: a word inside a negated sentence, "for now" matching inside nowhere, and an unwrap in a test. The scanner is costing more than it is catching right now, and because hygiene's steps are sequential with no if: always(), each one skips steps 6–10 — including check_stubs.py, which on #592 (the one PR that gets past step 2) found a real admission. Skipping #[cfg(test)] and #[test] bodies would be the single highest-value change to it.

For this PR alone, ZERO_LOW[ZERO_LOW.len() - 1].1 is the same assertion without the pattern.

2. This branch already contains the fix for #545's compile break.

#545 does not build: is_foreign and spawn_install are called but undefined there, merge casualties of its two origin/main merges. Both exist here:

  • src/process/foreign/registry.rs:40 defines is_foreign, and src/process/foreign/mod.rs:60 exports it — pub use registry::{clear, is_foreign, supervisor_of};
  • src/userspace/capsule_linux/install.rs:36 defines pub fn spawn_install(package: &str, pinned: &[u8; 32]) -> Result<u32, SpawnError>

So whoever fixes #545 has the signature to restore, and the question of whether #545 needs to land separately at all is worth asking: this branch contains it (50 of its 52 capsule_app_store files, plus three more) and contains #544 as well.

Minor

  1. 127 commits behind main, same as the whole linux: personality, store install, desktop and kernel fixes #567 lane. main has since wired build-aarch64 and boot-aarch64; linux: land the Linux lane on main; terminal linux command, signals to running threads, pipe waits, madvise, VFS store, Process Manager #593 met those lanes first and found a foreign_absent.rs stub six symbols behind the real module. This branch adds src/userspace/capsule_linux/install.rs and touches src/process/foreign, so it will meet the same thing.
  2. 67c960283 is "add frame_foot.rs, which 3ab3fcd declared and left out" — a module declared in a mod list and never committed. Same class as Anyone network in the browser, a standards-based engine, and a fast network path #589's vectors/certs_cell.bin, which .gitignore's global *.bin swallowed. Worth a git status check against a clean clone before this lands, since two separate branches in this queue have now shipped a reference to a file that was not added.

Questions

  1. Was the probe/data-path split in 55c3c7f2b present anywhere else? The shape of the bug — a connection that validates in order to show a status line, beside one that carries the payload and does not — is a pattern, not a one-off, and capsule_browser and capsule_net_anon both have probe-like paths. One git grep for the other callers of the per-check *_flight functions would settle whether server_trusted_flight is now the only way in.
  2. nonos_vt is +7303 lines of new terminal/width handling. Does capsule_terminal's −1757 mean it now delegates width to nonos_vt, and if so is the old width code gone or still reachable? Two width tables that can disagree is how the help alignment ratchet in linux: personality, store install, desktop and kernel fixes #567 ended up unenforced.

Verified correct

  • The TLS gate cannot be bypassed by forgetting it. One caller, at the single RPC chokepoint, with the refusal ahead of every write. I checked for other callers: server_trusted_flight appears only in its own module, the mod.rs declaration and re-export, and fetch_rpc.rs:40.
  • The gate is a hard AND, not a score. Seven checks, all &&, no partial-credit path — so a future check added to the list blocks by default rather than needing to be wired into a verdict.
  • CertificateVerify is checked over the right transcript. cert_verify_ecdsa.rs with the leaf's own key over the transcript to the Certificate message, which is the TLS 1.3 definition; verifying it over anything else would be decorative.
  • An unreadable clock fails the call. rtc_stamp()? propagates None rather than defaulting to zero or skipping validity. A validity check that degrades to "no check" when the clock is unavailable is the usual way this gets broken.
  • The signable-amount cap is independent of the TLS fix. 49dffbb1e's 1000 gwei refusal holds even if the transport is compromised, which is what defence in depth means here.
  • The boot is clean. zk_attest_ok: 24, zk_attest_fail: 0, fatal: 0, panic: 0, on a branch that adds three compression libraries, an OpenPGP implementation and 7300 lines of terminal handling.
  • 112 lanes pass, including boot-smoke, extraction, lean, kani, verus, attestation, attestation-attack, adversarial, reproducible, supply-chain, trust-chain, trust-ledger, runnable-proofs, symbol-scan, section-size and proof-coverage.

CI at this head

Eight real failures: seven inherited from #567 in six causes, and hygiene, which is two false positives — one inherited, one this PR's. Nothing in the failing set reflects on the wallet, terminal or store work.

The TLS fix should not wait on the inherited red. If #567's six one-line fixes are going to take time, this commit is worth separating out and landing on its own.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants